package com.yea.loadbalancer.util;

import java.util.concurrent.atomic.AtomicLong;

public class MeasuredRate {
	private final AtomicLong _lastBucket = new AtomicLong(0);
	private final AtomicLong _currentBucket = new AtomicLong(0);
	private final long _sampleInterval;
	private volatile long _threshold;

	/**
	 * @param sampleInterval
	 *            in milliseconds
	 */
	public MeasuredRate(long sampleInterval) {
		_sampleInterval = sampleInterval;

		_threshold = System.currentTimeMillis() + sampleInterval;
	}

	/**
	 * Returns the count in the last sample interval
	 */
	public long getCount() {
		checkAndResetWindow();
		return _lastBucket.get();
	}

	/**
	 * Returns the count in the current sample interval which will be
	 * incomplete. If you are looking for accurate counts/interval - use
	 * {@link MeasuredRate#getCount()} instead.
	 */
	public long getCurrentCount() {
		checkAndResetWindow();
		return _currentBucket.get();
	}

	/**
	 * Increments the count in the current sample interval. If the current
	 * interval has exceeded, assigns the current count to the last bucket and
	 * zeros out the current bucket
	 */
	public void increment() {
		checkAndResetWindow();
		_currentBucket.incrementAndGet();
	}

	private void checkAndResetWindow() {
		long now = System.currentTimeMillis();
		if (_threshold < now) {
			_lastBucket.set(_currentBucket.get());
			_currentBucket.set(0);
			_threshold = now + _sampleInterval;
		}
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("count:" + getCount());
		sb.append("currentCount:" + getCurrentCount());
		return sb.toString();
	}

	public static void main(String args[]) {
		MeasuredRate mr = new MeasuredRate(500);

		for (int i = 0; i < 1000; i++) {
			mr.increment();
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		System.out.println("mr:" + mr);

	}
}
